﻿using System;
using System.Collections.Generic;
using System.Text;
using Lizk.SimpleHUD;
using SharpMedia.Controls;
using System.Diagnostics;
using System.IO;
using System.Data;
using MediaData;

namespace SharpMedia.Pages
{
    public class PlayerPage : MediaPage
    {
        public VideoList PlaybackList { get; private set; }
        public bool StopBetweenParts
        {
            get 
            {
                return contextPage.StopBetweenParts;
            }
            set 
            {
                contextPage.StopBetweenParts = value;
            }
        }

        private TimedTrigger<string> bottomBarTimer;
        private bool resumeAfterSeek, playbackStarted, playbackStopped;
        private HUDVideo2 video;
        private TimeSpan jumpAmount = new TimeSpan(0, 1, 0), seekAmount = new TimeSpan(0, 0, 15);
        private TimeSpan watchedAmount = TimeSpan.Zero;
        private DateTime lastPlay = DateTime.MinValue;
        private StopMenuPage smp;

        VideoContextPage contextPage;

        public bool CurrentFileIsDVD { get { return video.SourceUrl.ToLower().EndsWith(".ifo"); } }

        #region Controls
        
        private HUDContainerSimple ctnBottom;
        private HUDImageBox imgPlayerState;
        private HUDTimeBar seekBar;
        private HUDLabel labelDuration, labelCurrentFile, clock;
        #endregion

        public PlayerPage(MediaPage parent, VideoList list)
            : base(parent)
        {
            this.PlaybackList = list;
            Anchor = Anchor.All;
            if (list.Count == 0)
                throw new Exception("Playback list was empty!");

            AddRange(
                new HUDImage("white.png") // background
                {
                    Bounds = this.Bounds,
                    Anchor = Anchor.All,
                    ConstrainProportions = false,
                    Color = ColorS.Black,
                },

                video = new HUDVideo2(list.SelectedItem.File) 
                {
                    Bounds = this.Bounds,
                    Anchor = Anchor.All,
                    Alpha = 1,
                    Tag = true
                },

                ctnBottom = new HUDContainerSimple
                {
                    Bounds = new RectangleS(0, Bounds.Height, Bounds.Width, 80),
                    Anchor = Anchor.All ^ Anchor.Top
                }
            );

            video.StateChange += new EventHandler(video_StateChange);
            video.TrackChange += new EventHandler(video_TrackChange);

            ctnBottom.AddRange(
                // background
                new HUDImage("white.png") { Color = ColorS.Black, Alpha = 127, Anchor = Anchor.All, Size = ctnBottom.Size, ConstrainProportions = false },

                imgPlayerState = new HUDImageBox()
                {
                    DefaultImage = "pb_stop64.png",
                    Bounds = new RectangleS(30, 8, 64, 64),
                    Anchor = Anchor.Bottom | Anchor.Left
                },
                seekBar = new HUDTimeBar
                {
                    Bounds = new RectangleS(imgPlayerState.Bounds.Right + 20, 40, ctnBottom.Bounds.Width - imgPlayerState.Bounds.Right - 357, 27),
                    Anchor = Anchor.Left | Anchor.Right | Anchor.Bottom,
                    Alpha = 255,

                }

            );
            

            labelCurrentFile = new HUDLabel(list.SelectedItem.Name, "tahoma20b");
            labelCurrentFile.Color = Lizk.SimpleHUD.ColorS.White;
            labelCurrentFile.Alignment = Alignment.Bottom | Alignment.Left;
            labelCurrentFile.Anchor = Anchor.Left | Anchor.Top | Anchor.Right;
            labelCurrentFile.Bounds = new RectangleS(seekBar.Bounds.Left, 6, ctnBottom.Bounds.Width - seekBar.Bounds.Left, 30);
            ctnBottom.Add(labelCurrentFile);


            labelDuration = new HUDLabel("", "verdana22b");
            labelDuration.Color = Lizk.SimpleHUD.ColorS.White;
            labelDuration.Anchor = Anchor.Right ^ Anchor.Top;
            labelDuration.Alignment = Alignment.VCenter | Alignment.Left;
            labelDuration.Bounds = new RectangleS(seekBar.Bounds.Right + 5, seekBar.Bounds.Top, 93, seekBar.Bounds.Height);
            ctnBottom.Add(labelDuration);

            clock = new HUDLabel("00:00", "tahoma50b");
            clock.Color = ColorS.White;
            clock.Anchor = Anchor.Right | Anchor.Top;
            clock.Alignment = Alignment.Center | Alignment.VCenter;
            clock.Bounds = new RectangleS(ctnBottom.Bounds.Width - 160, 3, 160, 80);
            ctnBottom.Add(clock);


            seekBar.SeekBegun += new EventHandler(tb_SeekBegun);
            seekBar.SeekEnded += new EventHandler(tb_SeekEnded);

            bottomBarTimer = new TimedTrigger<string>(null, new TimeSpan(0, 0, 3));
            bottomBarTimer.FirstTrigger += new EventHandler(delegate { ctnBottom.Destination = new PointS(0,Bounds.Height -80); ctnBottom.DestinationSize = new SizeS(Bounds.Width, 80); });
            bottomBarTimer.TimeOut += new EventHandler(delegate { ctnBottom.Destination = new PointS(0, Bounds.Height); ctnBottom.DestinationSize = new SizeS(Bounds.Width, 80); });

            contextPage = new VideoContextPage(this, video);

            FadingStopped += new EventHandler(PlayerPage_FadingStopped);
        }

        void PlayerPage_FadingStopped(object sender, EventArgs e)
        {
            if (alpha == 255)
            {
                /*if (SharpMedia.Form.VSync == false)
                {
                    SharpMedia.Form.VSync = true;
                    SharpMedia.Form.ResetDevice();
                }*/
                video.Load();
            }
        }

        void video_TrackChange(object sender, EventArgs e)
        {
            contextPage.UpdateItems();
        }


        void video_StateChange(object sender, EventArgs e)
        {
            if (sender != video)
                return;

            if (!seekBar.IsSeeking)
            {
                if (video.State == HUDVideo2.PlayerState.Playing)
                {
                    lastPlay = DateTime.Now;
                }
                else
                {
                    if (lastPlay != DateTime.MinValue)
                        watchedAmount += DateTime.Now - lastPlay;
                    lastPlay = DateTime.MinValue;
                }

                switch (video.State)
                {
                    case HUDVideo2.PlayerState.NotLoaded:
                        imgPlayerState.CurrentImage = "pb_stop64.png";
                        break;
                    case HUDVideo2.PlayerState.Stopped:
                        imgPlayerState.CurrentImage = "pb_stop64.png";

                        if (!playbackStarted)
                        {
                            
                            video.Play();
                            playbackStarted = true;
                            SharpMedia.JobQueue.Enqueue(contextPage.UpdateItems);
                            
                        }
                        break;
                    case HUDVideo2.PlayerState.Playing:
                        imgPlayerState.CurrentImage = "pb_play64.png";
                        break;
                    case HUDVideo2.PlayerState.Paused:
                        imgPlayerState.CurrentImage = "pb_pause64.png";
                        break;
                    case HUDVideo2.PlayerState.Menu:
                        imgPlayerState.CurrentImage = "pb_pause64.png";
                        break;
                }

                SharpMedia.Engine.StayOnTop = video.State == HUDVideo2.PlayerState.Playing;

            }
        }

        void tb_SeekEnded(object sender, EventArgs e)
        {
            TimeSpan seek = seekBar.SeekAmount;
            
            if (video.Duration - seekBar.Position - seek < new TimeSpan(0, 0, 0, 1))
                seek -= CurrentFileIsDVD ? new TimeSpan(0, 0, 0, 2) : new TimeSpan(0,0,0,0,500);

            video.Seek(seek, false);
            if (!CurrentFileIsDVD)
            {
                if (resumeAfterSeek)
                    video.Play();
                else
                    video_StateChange(video, null);
            }
        }

        void tb_SeekBegun(object sender, EventArgs e)
        {
            resumeAfterSeek = video.State == HUDVideo2.PlayerState.Playing;
            if(!CurrentFileIsDVD)
            video.Pause();
            if (lastPlay != DateTime.MinValue)
                watchedAmount += DateTime.Now - lastPlay;
            lastPlay = DateTime.MinValue;
        }

        public override void Update(TimeSpan ts)
        {
            clock.Text = DateTime.Now.ToString("t");
            bottomBarTimer.Update();

            if (video.Closed && SharpMedia.CurrentPage == this)
                SharpMedia.Back();


            if (!CurrentFileIsDVD && !playbackStopped && playbackStarted && video.Duration.TotalMilliseconds - video.Position.TotalMilliseconds < 100 && video.Duration.Ticks > 0)
            {
                EndOfFile();
                playbackStopped = true;
                base.Update(ts);
                return;
            }
            
            
            if (!seekBar.IsSeeking && video.State == HUDVideo2.PlayerState.Playing)
            {
                seekBar.Duration = video.Duration;
                seekBar.Position = video.Position;
                labelDuration.Text = FormatTime(video.Duration);
            } else if(seekBar.IsSeeking)
                imgPlayerState.CurrentImage = seekBar.SeekAmount.TotalMilliseconds < 0 ? "pb_rewind64.png" : "pb_fastforward64.png";

            base.Update(ts);
        }

        private void EndOfFile()
        {

            if (!StopBetweenParts && PlaybackList.SelectedIndex + 1 < PlaybackList.Count)
            {
                PlaybackList.SelectedIndex++;
                SwitchFile();
            }
            else
            {
                video.Pause();
                ShowStopMenu(true);
            }
            
        }

        private void SetWatched()
        {
            if (CurrentFileIsDVD)
                return;

            if (lastPlay != DateTime.MinValue)
                watchedAmount += DateTime.Now - lastPlay;
            lastPlay = DateTime.MinValue;

            if (watchedAmount.Ticks > video.Duration.Ticks / 2)
            {
                Util.RunAsync(SaveWatched, Util.GetEpisodeFromPath(video.SourceUrl));
            }
            watchedAmount = TimeSpan.Zero;
        }

        private void SaveWatched(IEnumerable<MediaDataSet.EpisodesRow> episodes)
        {
            if (episodes == null)
                return;

            SharpMedia.WaitForLock();
            
            lock (SharpMedia.Database.Data.LockObject)
            {
                foreach (var episode in episodes)
                {
                    episode.Watched = 1;
                }
            }
            SharpMedia.WorkDone();
        }


        private void SwitchFile()
        {
            SetWatched();

            
            video.Close();
            video.Stop();
            HUDVideo2 v2 = new HUDVideo2(PlaybackList.SelectedItem.File);
            v2.Bounds = video.Bounds;
            v2.Anchor = Anchor.All;
            v2.StateChange += new EventHandler(video_StateChange);
            v2.TrackChange += new EventHandler(video_TrackChange);
            this[1] = v2;
            video = v2;
            contextPage.Video = video;
            playbackStarted = false;
            playbackStopped = false;
            video.Load();

            bottomBarTimer.Stop(true);

            contextPage.UpdateItems();
            labelCurrentFile.Text = PlaybackList.SelectedItem.Name;
        }

        private string FormatTime(TimeSpan ts)
        {
            string deString = string.Format("{0}:{1}", ts.Minutes.ToString().PadLeft(2, '0'), ts.Seconds.ToString().PadLeft(2, '0')); ;
            if (ts.Hours > 0)
            {
                deString = ts.Hours.ToString() + ":" + deString;
            }
            return deString;
        }

        public override void Close()
        {
            Fade(0, 2f);
            SetWatched();
            /*if (SharpMedia.Form.VSync == true)
            {
                SharpMedia.Form.VSync = false;
                SharpMedia.Form.ResetDevice();
            }*/
            video.Close();
            SharpMedia.Engine.StayOnTop = false;
        }

        public override void Show()
        {
            Fade(255, 2f);


            video.Fade(255, 2f);
        }

        public void DVDCommand(HUDCommands command, object tag)
        {
            switch (video.State)
            {
                case HUDVideo2.PlayerState.Playing:
                case HUDVideo2.PlayerState.Paused:
                    switch (command)
                    {
                        case HUDCommands.Select:
                            if (bottomBarTimer.Triggered)
                                bottomBarTimer.Stop(true);
                            else
                                bottomBarTimer.Trigger();
                            break;

                        case HUDCommands.Play:
                        case HUDCommands.Pause:
                        case HUDCommands.PlayPause:
                            if (video.State == HUDVideo2.PlayerState.Playing)
                            {
                                video.Pause();
                                bottomBarTimer.Trigger();
                                bottomBarTimer.Stop(false);
                            }
                            else if (video.State == HUDVideo2.PlayerState.Paused)
                            {
                                video.Play();
                                bottomBarTimer.Trigger();
                            }
                            break;
                        case HUDCommands.Right:
                        case HUDCommands.Forward:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount += seekAmount;
                            break;
                        case HUDCommands.Left:
                        case HUDCommands.Rewind:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount -= seekAmount;
                            break;

                        case HUDCommands.Up:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount -= jumpAmount;
                            break;
                        case HUDCommands.Down:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount += jumpAmount;
                            break;

                        case HUDCommands.Previous:
                            video.CurrentChapter--;
                            bottomBarTimer.Trigger();
                            break;
                        case HUDCommands.Next:
                            video.CurrentChapter++;
                            bottomBarTimer.Trigger();
                            break;
                        case HUDCommands.KeyPress:
                            break;
                    }
                    break;
                case HUDVideo2.PlayerState.Menu:
                    switch (command)
                    {
                        case HUDCommands.Up:
                            video.MenuMoveUp();
                            break;
                        case HUDCommands.Down:
                            video.MenuMoveDown();
                            break;
                        case HUDCommands.Left:
                            video.MenuMoveLeft();
                            break;
                        case HUDCommands.Right:
                            video.MenuMoveRight();
                            break;
                        case HUDCommands.Select:
                            video.MenuSelect();
                            break;

                    }
                    break;
            }


            switch (command)
            {
                case HUDCommands.Menu:
                    contextPage.UpdateItems();
                    if (contextPage.VOptions.Count > 0)
                    {
                        SharpMedia.Navigate(contextPage);
                    }
                    break;
                case HUDCommands.Preset1:
                    video.TitleMenu();
                    break;
                case HUDCommands.Stop:
                    video.Pause();
                    ShowStopMenu(false);
                    break;
                case HUDCommands.Back:
                    video.Close();
                    SharpMedia.Back();
                    break;
            }
        }

        public override void Command(HUDCommands command, object tag)
        {
            if (CurrentFileIsDVD)
            {
                DVDCommand(command, tag);
            }
            else
            {
                switch (command)
                {
                    case HUDCommands.Previous:
                    case HUDCommands.Up:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount -= jumpAmount;
                        break;
                    case HUDCommands.Next:
                    case HUDCommands.Down:
                            seekBar.SeekAmount += jumpAmount;
                            bottomBarTimer.Trigger();
                        break;
                    case HUDCommands.Rewind:
                    case HUDCommands.Left:
                            seekBar.SeekAmount -= seekAmount;
                            bottomBarTimer.Trigger();
                        break;
                    case HUDCommands.Forward:
                    case HUDCommands.Right:
                            bottomBarTimer.Trigger();
                            seekBar.SeekAmount += seekAmount;
                        break;
                    case HUDCommands.Select:
                        if (bottomBarTimer.Triggered)
                            bottomBarTimer.Stop(true);
                        else
                            bottomBarTimer.Trigger();
                        break;

                    case HUDCommands.Fullscreen:
                        if (video.State != HUDVideo2.PlayerState.NotLoaded && parent != null)
                            parent.Command(command, tag); ;
                        break;
                    case HUDCommands.Menu:
                        contextPage.UpdateItems();
                        if (contextPage.VOptions.Count > 0)
                        {
                            SharpMedia.Navigate(contextPage);
                        }
                        break;
                    case HUDCommands.Play:
                    case HUDCommands.Pause:
                    case HUDCommands.PlayPause:
                        if (seekBar.IsSeeking)
                        {
                            resumeAfterSeek = !resumeAfterSeek;
                            break;
                        }

                        if (video.State == HUDVideo2.PlayerState.Playing)
                        {
                            video.Pause();
                            bottomBarTimer.Trigger();
                            bottomBarTimer.Stop(false);
                        }
                        else if (video.State == HUDVideo2.PlayerState.Paused || video.State == HUDVideo2.PlayerState.Stopped)
                        {
                            video.Play();
                            bottomBarTimer.Trigger();
                        }
                        break;
                    case HUDCommands.Stop:
                        video.Pause();
                        ShowStopMenu(false);
                        break;
                    case HUDCommands.Back:
                        if (video.State != HUDVideo2.PlayerState.NotLoaded)
                        {
                            video.Close();
                            SharpMedia.Back();
                        }
                        break;

                    
                    default:
                        break;
                }



            }


            

        }

        private void ShowStopMenu(bool p)
        {
            smp = new StopMenuPage(PlaybackList, p, this);
            smp.FileSwitched += new EventHandler(delegate { SwitchFile(); });
            smp.StopPressed += new EventHandler(smp_StopPressed);
            smp.PlayPressed += new EventHandler(smp_PlayPressed);
            SharpMedia.JobQueue.Enqueue(delegate
            {
                if(!(SharpMedia.CurrentPage is StopMenuPage))
                    SharpMedia.Navigate(smp);
            });
        }

        void smp_PlayPressed(object sender, EventArgs e)
        {
            StopMenuPage smp = (StopMenuPage)sender;
            if (smp.EndOfTheLine)
            {
                video.Seek(TimeSpan.Zero, true);
            }
            video.Play();
            playbackStopped = false;
        }

        void smp_StopPressed(object sender, EventArgs e)
        {
            video.Close();
            SharpMedia.Back();
        }

    }

}
